package br.edu.ufcg.dsc.adsd.lotv.core;

import java.util.HashMap;
import java.util.Map;

import br.edu.ufcg.dsc.adsd.lotv.utils.Constants;

import eduni.simjava.Sim_entity;
import eduni.simjava.Sim_port;
import eduni.simjava.Sim_stat;
import eduni.simjava.Sim_system;

public abstract class Connectable extends Sim_entity {

	protected Map<String, Sim_port> ports;
	protected String gatewayPort;
	private Sim_stat stat;
	
	public Connectable(String id) {
		super(id);
		this.ports = new HashMap<String, Sim_port>();
		this.stat = new Sim_stat();
		this.stat.add_measure(Sim_stat.QUEUE_LENGTH);
		this.stat.add_measure(Sim_stat.RESIDENCE_TIME);
		this.stat.add_measure(Sim_stat.THROUGHPUT);
		this.stat.add_measure(Sim_stat.UTILISATION);
		this.stat.add_measure(Sim_stat.WAITING_TIME);
		this.stat.add_measure(Sim_stat.SERVICE_TIME);
		this.set_stat(this.stat);
	}
	
	protected Sim_port port(String name) {
		return this.ports.get(name);
	}
	
	/**
	 * Seta a porta que sai dessa entidade para a entidade gateway
	 * @param gateway A entidade conectable que é o gateway 
	 */
	public void defaultGW(Connectable gateway) {
		this.gatewayPort = portName(this, gateway);
	}
	
	/**
	 * Conecta duas portas previamente criadas e adicionada as respectivas entidades
	 * @param to Entidade de destino
	 * @param to_port Porta de destino na entidade de destino
	 * @param from_port Porta de origem na entidade de origem (no caso this)
	 */
	public void connect(Sim_entity to, String to_port, String from_port) {
		this.ports.put(from_port, this.get_port(from_port));
		Sim_system.link_ports(this.get_name(), from_port, to.get_name(), to_port);
	}
	
	/**
	 * Esse método deve criar uma par de portas de comunicação para
	 * duas entidades se comunicarem e as conecta
	 * @param to
	 * @return
	 */
	public String connect(Sim_entity to) {
		String portName = Connectable.portName(this, to);
		Sim_port srcPort = new Sim_port(portName);
		Sim_port dstPort = new Sim_port(portName);
		this.add_port(srcPort);
		to.add_port(dstPort);
		this.connect(to, portName, portName);
		return portName;
	}
	
	
	public static String portName(Sim_entity from, Sim_entity to) {
		return Constants.FROM_NAME + from.get_name() + 
				Constants.TO_NAME + to.get_name();
	}

}
